package com.beiming.libra.service.impl;

import com.beiming.libra.common.enums.CaseApplyEnum;
import com.beiming.libra.common.enums.CaseUserTypeEnum;
import com.beiming.libra.common.enums.DocumentTypeEuem;
import com.beiming.libra.common.utils.CommonsUtils;
import com.beiming.libra.dao.ArbitrationBookAttachmentMapper;
import com.beiming.libra.dao.UserMessageMapper;
import com.beiming.libra.domain.ArbitrationBookAttachment;
import com.beiming.libra.domain.UserMessage;
import com.beiming.libra.domain.dto.responsedto.DocmentInfoResponseDTO;
import com.beiming.libra.service.DocumentCreateService;
import com.beiming.libra.utils.DocumentUtil;
import com.google.common.base.Joiner;
import com.google.common.collect.Collections2;
import freemarker.template.TemplateException;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @Auther: tyrion
 * @Date: 2018/6/11 11:52
 * @类描述:
 */
@Service
@Slf4j
public class DocumentCreateServiceImpl implements DocumentCreateService {

  private static Logger logger = LoggerFactory.getLogger(DocumentCreateServiceImpl.class);
  @Value("${file.document.dir}")
  private String dir;

  @Autowired
  ArbitrationBookAttachmentMapper arbitrationBookAttachmentMapper;

  @Autowired
  UserMessageMapper userMessageMapper;


  // 提供接口出去
  public void createDocument(String caseId, String docType) {
    if (StringUtils.equals(docType, DocumentTypeEuem.ACCEPT_INFORM_BOOK.getCode())) {
      acceptInformBookCreate(caseId); // 受理通知书
    } else if (StringUtils.equals(docType, DocumentTypeEuem.PROOF_PROVIDE_BOOK.getCode())) {
      proofProvideBookCreate(caseId); //举证通知书
    } else if (StringUtils.equals(docType, DocumentTypeEuem.JUDGE_INFORM_BOOK.getCode())) {
      judgeInformBookCreate(caseId); //应裁通知书
    } else if (StringUtils.equals(docType, DocumentTypeEuem.ARBITRATOR_STATE_BOOK.getCode())) {
      arbitratorStateBookCreate(caseId); //仲裁员声明书
    } else if (StringUtils.equals(docType, DocumentTypeEuem.FEE_APPROVAL_BOOK.getCode())) {
      feeApprovalBookCreate(caseId); //仲裁费审定单
    } else if (StringUtils.equals(docType, DocumentTypeEuem.ARBITRATION_APPLY_BOOK.getCode())) {
      arbitrationApplyBookCreate(caseId); //仲裁申请书
    } else if (StringUtils.equals(docType, DocumentTypeEuem.ARBITRATION_ANSWER_BOOK.getCode())) {
      arbitrationAnswerBookCreate(caseId); // 仲裁答辩书
    } else if (StringUtils.equals(docType, DocumentTypeEuem.ACCREDIT_ENTRUST_BOOK.getCode())) {
      accreditEntrustBookCreate(caseId); //授权委托书
    } else if (StringUtils
        .equals(docType, DocumentTypeEuem.COURT_MEMBERS_APPROVAL_BOOK.getCode())) {
      courtMembersApprovalBookCreate(caseId); //仲裁庭组成人员审定单
    } else if (StringUtils
        .equals(docType, DocumentTypeEuem.CHANGE_LITIGANT_INFORM_BOOK.getCode())) {
      changeLitigantInformBookCreate(caseId); //变更当事人通知书
    } else if (StringUtils.equals(docType, DocumentTypeEuem.ARCHIVE_APPROVE_BOOK.getCode())) {
      archiveApproveBookCreate(caseId); //归档审批表
    } else {
      //TODO 待添加。。
      // TODO 杭州仲裁委员会仲裁员廉政承诺书、保密承诺书
    }
  }

  /**
   * 受理通知书
   */
  @Transactional
  private void acceptInformBookCreate(String caseId) {

    DocumentTypeEuem docTypeEuem = DocumentTypeEuem.ACCEPT_INFORM_BOOK; //受理通知书

    //查询数据
    List<DocmentInfoResponseDTO> listBook = arbitrationBookAttachmentMapper.getDocmentInfo(caseId);
    if (listBook != null && !listBook.isEmpty()) {
      //开始封装数据
      Map<String, Object> dataMap = new HashMap<>();
      DocmentInfoResponseDTO aibr = listBook.get(0);
      dataMap.put("caseNo", aibr.getCaseNo());
      dataMap.put("disputeType", CaseApplyEnum.getName(Integer.valueOf(aibr.getDisputeType())));
      dataMap.put("acceptAmount", aibr.getAcceptAmount());
      dataMap.put("disposeAmount", aibr.getDisposeAmount());
      //申请人
      String applicantName = getApplicantNamesInlist(listBook);
      //被申请人
      String respondentName = getRespondentNamesInList(listBook);

      dataMap.put("applicantName", applicantName);
      dataMap.put("respondentName", respondentName);
      dataMap.put("date", getFormatDate());

      File destFile = docOperate(caseId, docTypeEuem, dataMap);

      // 发送消息提醒 TODO 确认要发送给哪些人
      listBook.forEach(book -> {
        sendMessage(caseId, destFile, book.getUserId(), aibr.getCaseName(),
            docTypeEuem);
      });
    }
  }


  /**
   * 举证通知书
   */
  private void proofProvideBookCreate(String caseId) {
    DocumentTypeEuem docTypeEuem = DocumentTypeEuem.PROOF_PROVIDE_BOOK; //举证通知书

    //查询数据
    List<DocmentInfoResponseDTO> listBook = arbitrationBookAttachmentMapper
        .getDocmentInfo(caseId);
    if (listBook != null && !listBook.isEmpty()) {
      //开始封装数据.get(0)
      Map<String, Object> dataMap = new HashMap<>();
      DocmentInfoResponseDTO aibr = listBook.get(0);
      dataMap.put("caseNo", aibr.getCaseNo());
      //申请人
      String applicantName = getApplicantNamesInlist(listBook);
      dataMap.put("applicantName", applicantName);
      dataMap.put("date", getFormatDate());
      dataMap.put("docNum", listBook.size()); //仲裁员和对方当事人的人数 TODO 待确认

      File destFile = docOperate(caseId, docTypeEuem, dataMap);

      // 发送消息提醒 TODO 确认要发送给哪些人
      listBook.forEach(book -> {
        sendMessage(caseId, destFile, book.getUserId(), aibr.getCaseName(),
            docTypeEuem);
      });
    }
  }


  /**
   * 应裁通知书
   */
  private void judgeInformBookCreate(String caseId) {
    DocumentTypeEuem docTypeEuem = DocumentTypeEuem.JUDGE_INFORM_BOOK; //应裁通知书

    //查询数据
    List<DocmentInfoResponseDTO> listBook = arbitrationBookAttachmentMapper
        .getDocmentInfo(caseId);
    if (listBook != null && !listBook.isEmpty()) {
      //开始封装数据
      Map<String, Object> dataMap = new HashMap<>();
      DocmentInfoResponseDTO aibr = listBook.get(0);
      dataMap.put("caseNo", aibr.getCaseNo());
      dataMap.put("disputeType", CaseApplyEnum.getName(Integer.valueOf(aibr.getDisputeType())));
      //申请人
      String applicantName = getApplicantNamesInlist(listBook);
      //被申请人
      String respondentName = getRespondentNamesInList(listBook);

      dataMap.put("applicantName", applicantName);
      dataMap.put("respondentName", respondentName);
      dataMap.put("docNum", listBook.size() + 1); //仲裁答辩书份数 TODO 待确认
      dataMap.put("docRevNum", listBook.size() + 1); //仲裁反请求申请书及其副本 TODO 待确认
      dataMap.put("date", getFormatDate());

      File destFile = docOperate(caseId, docTypeEuem, dataMap);

      // 发送消息提醒 TODO 确认要发送给哪些人
      listBook.forEach(book -> {
        sendMessage(caseId, destFile, book.getUserId(), aibr.getCaseName(),
            docTypeEuem);
      });
    }
  }

  /**
   * 仲裁员声明书
   */
  private void arbitratorStateBookCreate(String caseId) {
    DocumentTypeEuem docTypeEuem = DocumentTypeEuem.ARBITRATOR_STATE_BOOK; //仲裁员声明书

    //查询数据
    List<DocmentInfoResponseDTO> listBook = arbitrationBookAttachmentMapper
        .getDocmentInfo(caseId);
    if (listBook != null && !listBook.isEmpty()) {
      //开始封装数据
      Map<String, Object> dataMap = new HashMap<>();
      DocmentInfoResponseDTO aibr = listBook.get(0);
      dataMap.put("caseNo", aibr.getCaseNo());
      dataMap.put("disputeType", CaseApplyEnum.getName(Integer.valueOf(aibr.getDisputeType())));
      //申请人
      String applicantName = getApplicantNamesInlist(listBook);
      //被申请人
      String respondentName = getRespondentNamesInList(listBook);

      dataMap.put("applicantName", applicantName);
      dataMap.put("respondentName", respondentName);
      dataMap.put("date", getFormatDate());
      dataMap.put("arbitrator", aibr.getArbitratorName());
      File destFile = docOperate(caseId, docTypeEuem, dataMap);

      // 发送消息提醒 TODO 确认要发送给哪些人
      listBook.forEach(book -> {
        sendMessage(caseId, destFile, book.getUserId(), aibr.getCaseName(),
            docTypeEuem);
      });
    }
  }

  /**
   * 仲裁申请书 TODO 表里没有用户年龄、职业、工作单位地址等
   *    TODO 证据材料怎么拿，待确认。。。。。。
   */
  private void arbitrationApplyBookCreate(String caseId) {
    DocumentTypeEuem docTypeEuem = DocumentTypeEuem.ARBITRATION_APPLY_BOOK; //仲裁申请书

    //查询数据
    List<DocmentInfoResponseDTO> listBook = arbitrationBookAttachmentMapper
        .getDocmentInfo(caseId);
    if (listBook != null && !listBook.isEmpty()) {
      //开始封装数据
      Map<String, Object> dataMap = new HashMap<>();
      DocmentInfoResponseDTO air = listBook.get(0);
      air.setDisputeType(CaseApplyEnum.getName(Integer.valueOf(air.getDisputeType())));
//      dataMap.put("disputeType", CaseApplyEnum.getName(Integer.valueOf(aibr.getDisputeType())));
      //申请人
      String applicantName = getApplicantNamesInlist(listBook);
      //被申请人
      String respondentName = getRespondentNamesInList(listBook);
      dataMap.put("air", air);
      dataMap.put("applicantName", applicantName);
      dataMap.put("respondentName", respondentName);
      dataMap.put("date", getFormatDate());
      //申请人信息
      Collection<DocmentInfoResponseDTO> aList = Collections2.filter(listBook,
          book -> CaseUserTypeEnum.APPLICANT.getCode().equals(book.getUserType()));
      dataMap.put("alist", aList);
      //被申请人列表
      Collection<DocmentInfoResponseDTO> rList = Collections2.filter(listBook,
          book -> CaseUserTypeEnum.APPLICANT.getCode().equals(book.getUserType()));
      dataMap.put("aList", aList);
      dataMap.put("rList", rList);
      //TODO 证据信息
      // TODO 物证、书证份数
      //TODO 申请书副本多少份

      File destFile = docOperate(caseId, docTypeEuem, dataMap);

      // 发送消息提醒 TODO 确认要发送给哪些人
      listBook.forEach(book -> {
        sendMessage(caseId, destFile, book.getUserId(), air.getCaseName(),
            docTypeEuem);
      });
    }
  }

  /**
   * 仲裁费审定单 TODO
   */
  private void feeApprovalBookCreate(String caseId) {

  }

  /**
   * 仲裁答辩书 TODO
   */
  private void arbitrationAnswerBookCreate(String caseId) {

  }

  /**
   * 授权委托书 TODO
   */
  private void accreditEntrustBookCreate(String caseId) {

  }

  /**
   * 仲裁庭组成人员审定单 TODO
   */
  private void courtMembersApprovalBookCreate(String caseId) {

  }

  /**
   * 变更当事人通知书 TODO
   */
  private void changeLitigantInformBookCreate(String caseId) {

  }

  /**
   * 归档审批表 TODO
   */
  private void archiveApproveBookCreate(String caseId) {

  }

// ==================================公共方法=================================

  /**
   * 文书操作封装
   */
  private File docOperate(String caseId, DocumentTypeEuem docTypeEuem,
      Map<String, Object> dataMap) {
    DestFile df = new DestFile(caseId).invoke();
    File destFileTemp = df.getDestFileTemp();
    File destFile = df.getDestFile();
    //查看该类型文书是否存在，存在则删除
    arbitrationBookAttachmentMapper.deleteBycaseIdAndType(caseId,
        docTypeEuem.getCode());
    DocumentUtil util = new DocumentUtil();
    String templateName = docTypeEuem.getTemplateName();
    try {
      util.documentBookCreate(destFileTemp.getAbsolutePath(), destFile.getAbsolutePath(),
          dataMap, templateName);
      logger.info("{}文书生成完成", docTypeEuem.getName());
    } catch (IOException e) {
      logger.error("文书生成错误:", e);
    } catch (TemplateException e) {
      logger.error("文书生成错误:", e);
    }

    //附件保存到表里
    saveToBookAttachment(caseId, docTypeEuem, docTypeEuem.getName() + ".docx", destFile, null);
    return destFile;
  }
  /**
   * 格式化日期
   */
  private String getFormatDate() {
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
    return dtf.format(LocalDateTime.now());
  }

  /**
   * 发送消息提醒公共方法
   */
  private void sendMessage(String caseId, File destFile, String receiverId, String caseName,
      DocumentTypeEuem docTypeEuem) {
    UserMessage um = new UserMessage();
    um.setId(CommonsUtils.get32BitUUID());
    um.setMessageTitle("案件：" + caseName + "发送+" + docTypeEuem.getName() + "+!!!");
    um.setMessageContent(
        "(需要优化,是否用模板)案件url:" + File.separator + caseId + File.separator + destFile.getName());
    um.setReceiverId(receiverId);
    um.setCaseId(caseId);
    um.setMessageType("0");
    um.setDocType(docTypeEuem.getCode());
    userMessageMapper.insertUserMessage(um);
  }

  /**
   * 保存附件公共方法
   */
  private void saveToBookAttachment(String caseId, DocumentTypeEuem docTypeEuem, String fileName,
      File destFile, String userId) {
    ArbitrationBookAttachment aba = new ArbitrationBookAttachment();
    aba.setId(CommonsUtils.get32BitUUID());
    aba.setCaseId(caseId);
    aba.setDocType(docTypeEuem.getCode());
    aba.setName(fileName);
    aba.setUrl(File.separator + caseId + File.separator + destFile.getName());
    aba.setUserId(userId); //设接收人，预留 TODO
    arbitrationBookAttachmentMapper.insertBookAttachment(aba);
  }


  /**
   * 拿到申请人信息字符串
   */
  private String getApplicantNamesInlist(List<DocmentInfoResponseDTO> listBook) {
    String applicantName; //过滤：申请人
    Collection<DocmentInfoResponseDTO> aListBook = Collections2.filter(listBook,
        book -> CaseUserTypeEnum.APPLICANT.getCode().equals(book.getUserType()));
    //拿到姓名字段
    Collection<String> applicantNames = Collections2.transform(aListBook,
        a -> a.getUserName());
    applicantName = Joiner.on(",").join(applicantNames); //数组转字符串
    return applicantName;
  }

  /**
   * 拿到被申请人姓名字符串
   */
  private String getRespondentNamesInList(List<DocmentInfoResponseDTO> listBook) {
    String respondentName;
    Collection<DocmentInfoResponseDTO> rListBook = Collections2.filter(listBook,
        book -> CaseUserTypeEnum.RESPONDENT.getCode().equals(book.getUserType()));
    //拿到姓名字段
    Collection<String> respondentNames = Collections2.transform(rListBook,
        a -> a.getUserName());
    respondentName = Joiner.on(",").join(respondentNames);
    return respondentName;
  }

  /**
   * 获取文件路径公共内部类
   */
  private class DestFile {

    private String caseId;
    private File destFileTemp;
    private File destFile;

    public DestFile(String caseId) {
      this.caseId = caseId;
    }

    public File getDestFileTemp() {
      return destFileTemp;
    }

    public File getDestFile() {
      return destFile;
    }

    public DestFile invoke() {
      File destDir = new File(
          dir + File.separator + caseId);
      if (!destDir.exists()) {
        destDir.mkdirs();
      }
      destFileTemp = new File(
          destDir.getAbsoluteFile() + File.separator + UUID.randomUUID().toString().replace("-", "")
              + ".docx");
      destFile = new File(destDir.getAbsoluteFile() + File.separator
          + UUID.randomUUID().toString().replace("-", "") + ".docx");
      return this;
    }
  }


}
